#pragma once

#include "Common.h"
#include "ThreadCache.h"
#include "PageCache.h"
#include "ObjectPool.h"

// 线程局部存储指针，每个线程拥有自己独立的ThreadCache实例
static thread_local ThreadCache* pTLSThreadCache = nullptr;

/**
 * 并发内存分配函数
 * @param size 请求分配的内存大小
 * @return 分配的内存地址
 */
static void* ConcurrentAlloc(size_t size)
{
    // 大内存分配(超过256KB)直接走PageCache
    if (size > MAX_BYTES)
    {
        // 计算对齐后的大小和需要的页数
        size_t alignSize = SizeClass::RoundUp(size);
        size_t kpage = alignSize >> PAGE_SHIFT;

        // 加锁保护PageCache操作
        PageCache::GetInstance()->_pageMtx.lock();
        Span* span = PageCache::GetInstance()->NewSpan(kpage);
        span->_objSize = size;  // 记录分配大小用于后续释放
        PageCache::GetInstance()->_pageMtx.unlock();

        // 将页号转换为实际地址
        void* ptr = (void*)(span->_pageId << PAGE_SHIFT);
        return ptr;
    }
    else
    {
        // 小内存分配走ThreadCache
        // 通过TLS(线程局部存储)获取每个线程专属的ThreadCache实例
        if (pTLSThreadCache == nullptr)
        {
            static ObjectPool<ThreadCache> tcPool;  // 使用对象池创建ThreadCache
            pTLSThreadCache = tcPool.New();        // 从对象池分配
        }

        // 调用ThreadCache分配内存
        return pTLSThreadCache->Allocate(size);
    }    
}

/**
 * 并发内存释放函数
 * @param ptr 要释放的内存地址
 */
static void ConcurrentFree(void* ptr)
{
    // 获取内存块所属的Span
    Span* span = PageCache::GetInstance()->MapObjectToSpan(ptr);
    size_t size = span->_objSize;

    // 大内存直接释放回PageCache
    if (size > MAX_BYTES)
    {
        PageCache::GetInstance()->_pageMtx.lock();
        PageCache::GetInstance()->ReleaseSpanToPageCache(span);
        PageCache::GetInstance()->_pageMtx.unlock();
    }
    else
    {
        // 小内存释放回ThreadCache
        assert(pTLSThreadCache);  // 确保线程缓存已初始化
        pTLSThreadCache->Deallocate(ptr, size);
    }
}